package com.jjc.android.util;

import android.content.Context;
import android.graphics.Color;
import android.text.Editable;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;

import org.xml.sax.XMLReader;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class HtmlTagHandler implements Html.TagHandler {

    private final String tag;
    private final Context context;
    private final HashMap<String, String> attributes = new HashMap<>();
    private int startIndex = 0;

    public HtmlTagHandler(String tag, Context context) {
        this.tag = tag;
        this.context = context;
    }

    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        if (this.tag.equalsIgnoreCase(tag)) {
            processAttributes(xmlReader);
            if (opening) {
                startHandleTag(output);
            } else {
                endHandleTag(output);
                attributes.clear();
            }
        }
    }

    private void processAttributes(XMLReader xmlReader) {
        try {
            Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");
            elementField.setAccessible(true);
            Object element = elementField.get(xmlReader);
            assert element != null;
            Field attsField = element.getClass().getDeclaredField("theAtts");
            attsField.setAccessible(true);
            Object atts = attsField.get(element);
            assert atts != null;
            Field dataField = atts.getClass().getDeclaredField("data");
            dataField.setAccessible(true);
            String[] data = (String[]) dataField.get(atts);
            Field lengthField = atts.getClass().getDeclaredField("length");
            lengthField.setAccessible(true);
            Object attsLength = lengthField.get(atts);
            int len = attsLength == null ? 0 : (Integer) attsLength;
            for (int i = 0; i < len; i++) {
                assert data != null;
                attributes.put(data[i * 5 + 1], data[i * 5 + 4]);
            }

        } catch (Exception ignored) {}
    }

    private void startHandleTag(Editable output) {
        startIndex = output.length();
    }

    private void endHandleTag(Editable output) {
        int stopIndex = output.length();
        String style = attributes.get("style");
        if (!TextUtils.isEmpty(style)) {
            assert style != null;
            analysisStyle(startIndex, stopIndex, output, style);
        }
    }

    /**
     * 解析style属性
     *
     * @param startIndex startIndex
     * @param stopIndex stopIndex
     * @param editable editable
     * @param style style
     */
    private void analysisStyle(int startIndex, int stopIndex, Editable editable, String style) {
        String[] attrArray = style.split(";");
        Map<String, String> attrMap = new HashMap<>();
        for (String attr : attrArray) {
            String[] keyValueArray = attr.split(":");
            if (keyValueArray.length == 2) {
                // 去除前后空格
                attrMap.put(keyValueArray[0].trim(), keyValueArray[1].trim());
            }
        }
        String color = attrMap.get("color");
        if (!TextUtils.isEmpty(color)) {
            assert color != null;
            if (color.startsWith("rgb")) {
                color = color.replace("rgb(", "");
                color = color.replace(")", "");
                String[] rgbs = color.split(", ");
                color = toHex(Integer.parseInt(rgbs[0]), Integer.parseInt(rgbs[1]), Integer.parseInt(rgbs[2]));
            }

            try {
                editable.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String fontSize = attrMap.get("font-size");
        if (!TextUtils.isEmpty(fontSize)) {
            assert fontSize != null;
            fontSize = fontSize.split("px")[0];
            try {
                int size = sp2px(context, Integer.parseInt(fontSize));
                editable.setSpan(new AbsoluteSizeSpan(size), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    private static String toHex(int r, int g, int b) {
        return "#" + toBrowserHexValue(r) + toBrowserHexValue(g)
                + toBrowserHexValue(b);
    }

    private static String toBrowserHexValue(int number) {
        StringBuilder builder = new StringBuilder(
                Integer.toHexString(number & 0xff));
        while (builder.length() < 2) {
            builder.append("0");
        }
        return builder.toString().toUpperCase();
    }

    private static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }
}


